package com.jinsp.router_api;

import java.util.HashMap;

/**
 * Created by luoshuai on 12/13/21
 * <p>
 * 实现LRU功能
 */
public class RouterLruCache<K, V> {

    private final int maxCapacity;                    // 2~int最大值
    private final HashMap<K, Node<K, V>> map;          //存储节点数据
    private Node<K, V> head, tail;              //节点头，尾，双向链表

    public RouterLruCache(int maxCapacity) {
        maxCapacity = Math.max(2, Math.min(maxCapacity, Integer.MAX_VALUE));
        this.maxCapacity = maxCapacity;
        map = new HashMap<>(maxCapacity);
    }

    /**
     * 存储键值对数据
     *
     * @param key   键
     * @param value 值
     */
    public void put(K key, V value) {
        Node<K, V> node = map.get(key);
        if (node != null) {
            //直接替换原值并将节点移到首位
            node.value = value;
            moveNodeToTail(node);
            return;
        }
        //查看是否达到最大值
        if (map.size() >= maxCapacity) {
            //移除头节点
            if (head != null) {
                Node<K, V> headNextNode = head.next;
                headNextNode.pre = null;
                head.next = null;
                head = headNextNode;
            }
        }
        //创建Node并添加
        node = new Node<>();
        node.key = key;
        node.value = value;
        map.put(key, node);
        if (head == null) {
            head = node;
            return;
        }
        //放在尾节点
        if (tail == null) {
            head.next = node;
            node.pre = head;
        } else {
            tail.next = node;
            node.pre = tail;
        }
        tail = node;
    }

    /**
     * 根据Key获取对应值并将该节点重新放到首位
     *
     * @param key 键
     * @return 该键对应的值
     */
    public V get(K key) {
        Node<K, V> node = map.get(key);
        if (node == null) {
            return null;
        }
        moveNodeToTail(node);
        return node.value;
    }

    public void clear() {
        if (map.size() > 0) {
            map.clear();
            //清除首位节点
            head.next.pre = null;
            head.next = null;
            head = null;
            tail.pre.next = null;
            tail.pre = null;
            tail = null;
        }
    }

    /**
     * 将节点移动到尾部
     *
     * @param node 节点
     */
    private void moveNodeToTail(Node<K, V> node) {
        if (tail != null) {
            if (node == tail) {
                return;
            }
            if (node == head) {
                //重新设置头节点
                node.next.pre = null;
                head = node.next;
            } else {
                if (node.pre != null) {
                    //移动节点到尾部
                    node.pre.next = node.next;
                    node.next.pre = node.pre;
                }
            }
            node.next = null;
            tail.next = node;
            node.pre = tail;
        }
        tail = node;
    }

    @Override
    public String toString() {
        if (map == null || head == null) {
            return null;
        }
        //打印链表信息
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        builder.append(", ").append(head.key).append("=").append(head.value);
        Node<K, V> next = head.next;
        while (next != null) {
            builder.append(", ").append(next.key).append("=").append(next.value);
            next = next.next;
        }
        builder.append("}");
        return builder.delete(1, 3).toString();
    }

    private static class Node<K, V> {

        K key;
        V value;
        Node<K, V> next;
        Node<K, V> pre;
    }
}
